#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>


#define DEVICE_NAME "hello_driver"
#define SIZE(x,y) (x < y ? x : y)  // Return the smaller of two values

static int major = 0;  // Major number for the device
static char hello_buf[1024];  // Buffer for storing data
static struct class *hello_class;  // Device class structure

// Called when device is opened
static int hello_open(struct inode *node, struct file *file){
    printk(KERN_INFO "%s : open called !\n", __FUNCTION__);
    return 0;
}

// Called when device is closed
static int hello_close(struct inode *node, struct file *file){
    printk(KERN_INFO "%s : close called !\n", __FUNCTION__);
    return 0;
}

// Called when reading from device
static ssize_t hello_read(struct file *file, char __user *buf, size_t size, loff_t *offset){
    int err ;

    printk(KERN_INFO "%s : read called !\n", __FUNCTION__);
    err = copy_to_user(buf, hello_buf, SIZE(1024, size));  // Copy data to user space
    {
        if(err != 0){
            printk(KERN_ERR "%s: copy_to_user error!\n", __FUNCTION__);
            return -EFAULT;  // Return bad address error
        }
    }
    return SIZE(1024, size);  // Return number of bytes read
}

// Called when writing to device
static ssize_t hello_write(struct file *file, const char __user *buf, size_t size, loff_t *offset){
    int err ;
    printk(KERN_INFO "%s : open called !\n", __FUNCTION__);
    err = copy_from_user(hello_buf, buf, SIZE(1024, size));  // Copy data from user space
    {
        if(err != 0){
            printk(KERN_ERR "%s: copy_from_user error!\n", __FUNCTION__);
            return -EFAULT;  // Return bad address error
        }
    }
    return SIZE(1024, size);  // Return number of bytes written
}

// File operations structure
static struct file_operations hello_drv = {
	.owner		= THIS_MODULE,  // Owner module
	.read		= hello_read,   // Read operation
	.write		= hello_write,  // Write operation
	.open		= hello_open,   // Open operation
	.release    = hello_close,  // Close operation
};

// Module initialization function
static int __init hello_init(void){
    int err = 0;
    major = register_chrdev(major, DEVICE_NAME, &hello_drv);  // Register character device
    if(major < 0){
        printk(KERN_ERR "%s: register_chardev error!\n", __FUNCTION__);
        return major;
    }

    hello_class = class_create(THIS_MODULE, "hello_class");  // Create device class
    PTR_ERR(hello_class);
    if(IS_ERR(hello_class)){
        unregister_chrdev(major, DEVICE_NAME);  // Cleanup if error
        return -1;
    }

    device_create(hello_class, NULL, MKDEV(major, 0), NULL, "hello");  // Create device node

    printk(KERN_INFO "registe char dev %s(%d) suucssfully\n",DEVICE_NAME, major);
    return 0;
}

// Module exit function
static void __exit hello_exit(void){
    device_destroy(hello_class,MKDEV(major,0));  // Remove device node
    unregister_chrdev(major, DEVICE_NAME);  // Unregister character device
    printk(KERN_INFO "device %s(%d) unregisted\n", DEVICE_NAME, major);
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_AUTHOR("fison");
MODULE_DESCRIPTION("hello");
MODULE_LICENSE("GPL");